Skip to content

fix: improve Ledger error handling for disconnect, retry, and pagination cp-7.77.0#28515

Merged
dawnseeker8 merged 39 commits into
mainfrom
fix/ledger-error-handling-28272
May 14, 2026
Merged

fix: improve Ledger error handling for disconnect, retry, and pagination cp-7.77.0#28515
dawnseeker8 merged 39 commits into
mainfrom
fix/ledger-error-handling-28272

Conversation

@dawnseeker8
Copy link
Copy Markdown
Contributor

@dawnseeker8 dawnseeker8 commented Apr 8, 2026

Description

Fixes multiple issues with Ledger hardware wallet error handling that caused confusing error dialogs when the device was disconnected, the Ethereum app was closed, or blind signing was disabled:

  1. Stale BLE transport cleanup#closeTransport now forces BLE disconnection even when the transport object is already null but a device ID remains, preventing the OS from keeping a stale connection that blocks reconnection.
  2. Broader transient error detection#isTransientBleError now falls back to message-based matching (e.g. "disconnected", "bluetooth", "gatt") for BLE errors that use generic Error names after a device power-cycle.
  3. Wrong-app command failure cleanup#handleWrongApp now closes the transport when openEthereumAppOnLedger or closeRunningAppOnLedger fails, preventing stale connections.
  4. Pagination device readinessnextPage/prevPage in LedgerSelectAccount now call ensureDeviceReady before fetching accounts, and only dismiss the blocking modal if it was actually shown (via a modalShown flag).
  5. Disconnect error classificationgetLedgerAccountsByOperation now detects disconnect errors and throws a user-friendly "device got disconnected" message instead of a generic error.
  6. Gitignore updates — Added .cursor/hooks/state/ to .gitignore to prevent Cursor IDE state files from being committed.

Changelog

CHANGELOG entry: Fixed Ledger hardware wallet error handling to properly recover from disconnects, app switching failures, and pagination errors

Related issues

Fixes: #28272

Manual testing steps

Feature: Ledger error handling on disconnect

  Scenario: User disconnects Ledger during account pagination
    Given the user has connected a Ledger device via Bluetooth
    And the Ledger Select Account screen is displayed

    When the user disconnects the Ledger device
    And the user taps Next Page
    Then the app should prompt the user to reconnect instead of showing a generic error

  Scenario: User switches apps on Ledger during operation
    Given the user has connected a Ledger device with the Ethereum app open

    When the user switches to a different app on the Ledger
    And an operation is attempted
    Then the app should detect the transient BLE error and retry the connection

  Scenario: Ledger is powered off during account fetch
    Given the user has connected a Ledger device via Bluetooth
    And the Ledger Select Account screen is displayed

    When the user powers off the Ledger device
    And the user taps Next Page or Previous Page
    Then the app should show a disconnect-specific error message
    And the blocking modal should not be incorrectly dismissed

Screenshots/Recordings

Before

N/A

After

N/A

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Medium Risk
Changes touch Ledger BLE transport cleanup/retry logic and account-pagination readiness gating, which can affect hardware-wallet connection stability and user flows. Risk is mitigated by expanded unit test coverage across adapter, error parsing, and UI pagination cases.

Overview
Improves Ledger Bluetooth robustness by forcing BLE cleanup even when the transport object is already cleared, and by expanding transient disconnect detection to include message-based matches; it also closes the transport when app-switch commands fail to avoid stale connections.

Updates LedgerSelectAccount pagination (nextPage/prevPage) to call ensureDeviceReady before fetching pages and to only dismiss the blocking modal if it was shown, preventing unnecessary modal flicker and avoiding pagination attempts when the device isn’t ready.

Enhances Ledger error classification by treating disconnect-like failures in getLedgerAccountsByOperation as a user-facing “disconnected” error, and broadens parseErrorByType to handle non-Error objects with Ledger-shaped name/statusCode; adds/updates unit tests across these scenarios.

Reviewed by Cursor Bugbot for commit 5e139f5. Bugbot is set up for automated code reviews on this repo. Configure here.

…ion (#28272)

- Force BLE cleanup in LedgerBluetoothAdapter#closeTransport even when
  transport is null but deviceId exists, preventing stale OS-level BLE
  connections from blocking reconnection after device power-cycle.
- Expand transient BLE error detection with message-based fallback so
  reconnection errors with generic Error names are retried instead of
  immediately surfaced as "Something went wrong".
- Close transport in #handleWrongApp when openEthereumApp/closeRunningApp
  fails (user cancelled on device), preventing stale transport on retry.
- Add ensureDeviceReady check before pagination in LedgerSelectAccount
  (nextPage/prevPage), surfacing the HW wallet bottom sheet for
  reconnection instead of showing cryptic "Unspecified error" inline.
- Add disconnect error detection in getLedgerAccountsByOperation before
  the generic catch-all to provide clearer error messages.
- Added `.cursor/hooks/state/` to `.gitignore` to prevent tracking of local state files generated by the Cursor tool.
@dawnseeker8 dawnseeker8 self-assigned this Apr 8, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 8, 2026

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

Comment thread AGENTS.md Outdated
Comment thread app/core/HardwareWallet/adapters/LedgerBluetoothAdapter.ts
@github-actions github-actions Bot added the risk-medium Moderate testing recommended · Possible bug introduction risk label Apr 9, 2026
…ssifying non-transient errors

The message-based fallback in #isTransientBleError matched any error
containing 'bluetooth' (case-insensitive), which misclassified
non-transient Bluetooth errors (permission failures, 'Bluetooth not
supported', 'Bluetooth is off') as transient. This triggered up to two
unnecessary retries with RETRY_DELAY_MS delays before the real error
surfaced.

Replace the broad 'bluetooth' pattern with specific connectivity-related
patterns: 'bluetooth connection' and 'bluetooth transfer'. The existing
'disconnected', 'connection lost', and 'gatt' patterns already cover
most BLE connectivity issues.

Also adds negative tests ensuring non-transient bluetooth errors like
permission denials and disabled-state errors are not retried.

Co-authored-by: Xiaoming Wang <dawnseeker8@users.noreply.github.com>
@github-actions github-actions Bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Apr 9, 2026
Replace the generic 'bluetooth' substring match with more specific
'bluetooth connection' and 'ble error' patterns to avoid misclassifying
non-transient errors (e.g. 'Bluetooth not supported', permission failures)
as transient, which would trigger unnecessary retries.

Add test to verify non-transient Bluetooth errors are not retried.

Co-authored-by: Xiaoming Wang <dawnseeker8@users.noreply.github.com>
@github-actions github-actions Bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Apr 9, 2026
@metamaskbot metamaskbot requested a review from a team as a code owner April 10, 2026 10:43
@nikolastoimenovski-consensys
Copy link
Copy Markdown

Thanks for the feedback @owencraston. Tested on Android and iOS, here is feedback for all the issues:

issue1 - Send trx while the ledger is disconnected:

The “ledger disconnected” error doesn’t appear, but the issue is reproducible only if the user taps “continue” before the Connection Lost screen disappears by itself after turning on the ledger. After that, if the user continues with the scenario, the trx will be success. The video is attached in the slack thread https://consensys.slack.com/archives/C05C8481HSB/p1775639674912209 , since the file size is too big to be attached here.

issue2 - Perform dapp signing while the ledger is disconnected:

The issue is reproducible. Video attached.

101.mov

ISSUE2: [Bug]: [Ledger] "Something went wrong" error is shown when the user tries to perform dapp signing while the ledger ETH “Blind singing” is disabled

Fixed.

ISSUE3: ISSUE3: "Bluetooth required" modal is presented even though the bluetooth is already enabled on both the Mobile and the Ledger device:

The issue is reproducible. Video attached.

102.MP4

ISSUE4: "Ledger disconnected" error is shown on Send/Swap/Bridge/Dapp sign if the user denies to open the ETH app in the first try

Fixed.

ISSUE5: "Unspecified error" message is shown after trying to use the pagination in the Select an Account screen if the ETH app is not open

Fixed.

@github-actions github-actions Bot added risk-low Low testing needed · Low bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Apr 13, 2026
Avoid false Bluetooth-required gating when entering scan mode without a device ID, and parse plain-object Ledger errors by name/status so disconnects map to actionable hardware wallet errors instead of generic unknown failures.

Made-with: Cursor
@github-actions github-actions Bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-low Low testing needed · Low bug introduction risk labels Apr 14, 2026
@dawnseeker8
Copy link
Copy Markdown
Contributor Author

dawnseeker8 commented Apr 14, 2026

Thanks for the feedback @owencraston. Tested on Android and iOS, here is feedback for all the issues:

issue1 - Send trx while the ledger is disconnected:

The “ledger disconnected” error doesn’t appear, but the issue is reproducible only if the user taps “continue” before the Connection Lost screen disappears by itself after turning on the ledger. After that, if the user continues with the scenario, the trx will be success. The video is attached in the slack thread https://consensys.slack.com/archives/C05C8481HSB/p1775639674912209 , since the file size is too big to be attached here.

issue2 - Perform dapp signing while the ledger is disconnected:

The issue is reproducible. Video attached.

101.mov
ISSUE2: [Bug]: [Ledger] "Something went wrong" error is shown when the user tries to perform dapp signing while the ledger ETH “Blind singing” is disabled

Fixed.

ISSUE3: ISSUE3: "Bluetooth required" modal is presented even though the bluetooth is already enabled on both the Mobile and the Ledger device:

The issue is reproducible. Video attached.

102.MP4
ISSUE4: "Ledger disconnected" error is shown on Send/Swap/Bridge/Dapp sign if the user denies to open the ETH app in the first try

Fixed.

ISSUE5: "Unspecified error" message is shown after trying to use the pagination in the Select an Account screen if the ETH app is not open

Fixed.

HI, @nikolastoimenovski-consensys i am unable to replicate the issue 3 in above list. can you clarify whether you have given metamask access bluetooth permission?

- Updated the mock implementation for `getFirstPage` and `getNextPage` in `Ledger.test.ts` to use `jest.mocked` for improved clarity and consistency in error handling tests related to disconnected devices.
@dawnseeker8 dawnseeker8 changed the title fix: improve Ledger error handling for disconnect, retry, and pagination fix: improve Ledger error handling for disconnect, retry, and pagination cp-7.77.0 May 13, 2026
Copy link
Copy Markdown
Contributor

@NicolasMassart NicolasMassart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline review finding on the new hook test.

Comment thread app/core/HardwareWallet/hooks/useDeviceConnectionFlow.test.ts Outdated
Copy link
Copy Markdown
Contributor

@NicolasMassart NicolasMassart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline review finding on pagination disconnect classification.

Comment thread app/core/Ledger/Ledger.ts Outdated
dawnseeker8 and others added 2 commits May 13, 2026 19:06
Co-authored-by: Nico MASSART <NicolasMassart@users.noreply.github.com>
Co-authored-by: Nico MASSART <NicolasMassart@users.noreply.github.com>
NicolasMassart
NicolasMassart previously approved these changes May 13, 2026
@github-project-automation github-project-automation Bot moved this from Needs dev review to Review finalised - Ready to be merged in PR review queue May 13, 2026
- Adjusted formatting of error message handling for improved readability and consistency in the `getLedgerAccountsByOperation` function within `Ledger.ts`.
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2f9e7f2. Configure here.

Comment thread app/core/HardwareWallet/adapters/LedgerBluetoothAdapter.ts
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeAccounts
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: medium
  • AI Confidence: 78%
click to see 🤖 AI reasoning details

E2E Test Selection:
All 10 changed files are focused on Ledger hardware wallet functionality:

  1. LedgerBluetoothAdapter.ts: BLE transport cleanup fixes - adds closeTransport() on error paths, handles stale connections when transport is already cleared, and expands transient BLE error detection to include message-based matching (not just error name).

  2. errors/parser.ts: Robustness improvements - parseErrorByName now accepts unknown type with proper null/type guards, and reorders parsing to check by name before message.

  3. useDeviceConnectionFlow.ts: Fixes false "Bluetooth required" errors on startup by only pre-gating transport check when a specific targetDeviceId is set (not in scan mode).

  4. Ledger.ts: Adds disconnect error detection in getLedgerAccountsByOperation to surface a specific "ledger disconnected" error message.

  5. LedgerSelectAccount/index.tsx: Fixes pagination (next/prev page) to call ensureDeviceReady before showing the loading modal, preventing modal state issues when device is not ready.

Tag Selection Rationale:

  • SmokeAccounts is selected because it covers hardware wallet account flows including "adding QR-based hardware wallet accounts" and account management workflows that exercise the Ledger integration path.
  • No dedicated Ledger/hardware wallet E2E tests exist in the test suite (confirmed by searching tests/ directory).
  • Changes are isolated to hardware wallet BLE/error handling code and don't affect shared navigation, confirmations, or other wallet flows.
  • The LedgerSelectAccount view is a navigation route in App.tsx but changes are limited to pagination and device readiness checks.

Confidence note: Confidence is 78 because there are no dedicated Ledger E2E tests in the suite, so SmokeAccounts is the best available proxy for hardware wallet account management coverage.

Performance Test Selection:
Changes are focused on Ledger hardware wallet BLE connection handling, error parsing, and UI state management for the LedgerSelectAccount view. These are bug fixes for error paths and edge cases in BLE connectivity - they do not affect rendering performance, data loading, account list rendering, or any of the critical user flows measured by performance tests. No performance test tags are warranted.

View GitHub Actions results

@sonarqubecloud
Copy link
Copy Markdown

@dawnseeker8 dawnseeker8 added this pull request to the merge queue May 14, 2026
Merged via the queue into main with commit dc9bd4f May 14, 2026
205 of 209 checks passed
@dawnseeker8 dawnseeker8 deleted the fix/ledger-error-handling-28272 branch May 14, 2026 15:16
@github-actions github-actions Bot locked and limited conversation to collaborators May 14, 2026
@metamaskbotv2 metamaskbotv2 Bot added the release-7.78.0 Issue or pull request that will be included in release 7.78.0 label May 14, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

QA Passed QA testing has been completed and passed release-7.78.0 Issue or pull request that will be included in release 7.78.0 risk-medium Moderate testing recommended · Possible bug introduction risk size-L team-be-trade BE Trade team

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

[Bug]: [Ledger] Errors are shown when the ledger is disconnected/ETH app closed/blind signing disabled

5 participants